//
//  ZYMemoryWarningMonitor.m
//  ZYWebImage
//
//  Created by wangzhipan on 2025/5/3.
//

#import "ZYMemoryWarningMonitor.h"
#import <pthread.h>
#import <UIKit/UIKit.h>
#import <execinfo.h>
#import <mach/mach.h>
#import <sys/sysctl.h>
#import "ZYCrashReportGenerator.h"

static const double kDefaultThreshold = 300.0;      //MB
static const NSTimeInterval kCheckInterval = 2;     //检测间隔

//内存警告级别
typedef NS_ENUM(NSInteger, ZYMemoryWarningLevel) {
    ZYMemoryWarningLevelNone = 0,       //无警告
    ZYMemoryWarningLevelMiddle,     //中度警告（接近阈值）
    ZYMemoryWarningLevelHigh,       //高度警告（超过阈值）
    ZYMemoryWarningLevelCritical    //严重警告（系统内存警告）
};

static BOOL g_isMonitoring = NO;
static double g_memoryThreshold = kDefaultThreshold;
static pthread_t g_monitorThread = NULL;



@interface ZYMemoryWarningMonitor()
@property (nonatomic, assign, getter=isRunning) BOOL isRunning;
@property (nonatomic, strong, nullable) NSLock *lock;

// 内存警告阈值（MB）
@property (nonatomic, assign) NSUInteger threshold;

@property (nonatomic, assign) CFAbsoluteTime lastWarningTime;
@property (nonatomic, assign) ZYMemoryWarningLevel lastWarningLevel;

// 内存使用历史记录
@property (nonatomic, strong, nullable) NSMutableArray<NSNumber *> *memoryUsageHistory;
@end

@implementation ZYMemoryWarningMonitor

static void* monitorThreadEntry(void *info)
{
    //设置线程名，方便调试以及定位问题
    pthread_setname_np("ZYMemoryWarningMonitor");
    
    // 提高线程优先级，确保监控线程不会被阻塞
    int policy = 0;
    struct sched_param param;
    pthread_getschedparam(pthread_self(), &policy, &param);
    param.sched_priority = sched_get_priority_max(policy);
    pthread_setschedparam(pthread_self(), policy, &param);
    
    ZYMemoryWarningMonitor *monitor = (__bridge ZYMemoryWarningMonitor *)info;
    
    while (g_isMonitoring) {
        @autoreleasepool {
            double usage = [monitor currentMemoryUsage];
            //记录
            [monitor p_addMemoryUsageToHistory:usage];
            
            //计算内存使用率
            double totalMemory = [monitor totalDeviceMemory];
            double usagePercentage = usage / totalMemory * 100;
            
            //判断警告级别
            ZYMemoryWarningLevel level = ZYMemoryWarningLevelNone;
            if (usage >= g_memoryThreshold) {
                level = ZYMemoryWarningLevelHigh;
            }
            else if (usage >= g_memoryThreshold * 0.8) {
                level = ZYMemoryWarningLevelMiddle;
            }
            
            // 处理内存警告
            if (level > ZYMemoryWarningLevelNone) {
                [monitor p_handleMemoryWarning:level
                                   memoryUsage:usage
                                    percentage:usagePercentage];
            }
            
            usleep(kCheckInterval * 1000000);
        }
    }
    
    return NULL;
}

+ (instancetype)sharedInstance
{
    static id _instance = NULL;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

- (instancetype)init
{
    if (self = [super init]) {
        _isRunning = NO;
        _lastWarningTime = 0;
        _lastWarningLevel = ZYMemoryWarningLevelNone;
        _threshold = kDefaultThreshold;
        _lock = [NSLock new];
        _memoryUsageHistory = [NSMutableArray array];
    }
    return self;
}

- (BOOL)start
{
    return [self startWithThreshold:kDefaultThreshold];
}

- (BOOL)startWithThreshold:(double)threshold
{
    if (self.isRunning) {
        return YES;
    }
    
    [self.lock lock];
    
    //设置阈值
    self.threshold = threshold > 0 ? threshold : kDefaultThreshold;
    g_memoryThreshold = self.threshold;
    
    self.lastWarningTime = 0;
    self.lastWarningLevel = ZYMemoryWarningLevelNone;
    [self.memoryUsageHistory removeAllObjects];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(p_receiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
    
    g_isMonitoring = YES;
    _isRunning = YES;
    
    //创建线程并启动监控
    if (pthread_create(&g_monitorThread, NULL, monitorThreadEntry, (__bridge void *)self) != 0) {
        NSLog(@"无法创建监控线程");
        g_isMonitoring = NO;
        _isRunning = NO;
        [[NSNotificationCenter defaultCenter] removeObserver:self];
        [self.lock unlock];
        return NO;
    }
    
    [self.lock unlock];
    return YES;
}

- (BOOL)isRunning
{
    BOOL result = NO;
    [self.lock lock];
    result = _isRunning;
    [self.lock unlock];
    return result;
}

- (void)stop
{
    if (!self.isRunning) {
        return;
    }
    
    [self.lock lock];
    
    _isRunning = NO;
    g_isMonitoring = NO;
    
    if (g_monitorThread) {
        pthread_join(g_monitorThread, NULL);
        g_monitorThread = NULL;
    }
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self.memoryUsageHistory removeAllObjects];
    
    [self.lock unlock];
}

- (double)currentMemoryUsage
{
    // 获取app当前内存使用情况
    mach_task_basic_info_t taskInfo;
    mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
    kern_return_t kr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&taskInfo, &count);
    
    if (kr != KERN_SUCCESS) {
        return 0;
    }
    
    // 转换为 MB
    return taskInfo->resident_size / (1024.0 * 1024.0);
}

- (double)totalDeviceMemory
{
    // 获取设备总内存
    int mib[2] = {CTL_HW, HW_MEMSIZE};
    u_int namelen = sizeof(mib) / sizeof(mib[0]);
    uint64_t memSize = 0;
    size_t len = sizeof(memSize);

    if (sysctl(mib, namelen, &memSize, &len, NULL, 0) < 0) {
       return 0;
    }

    // 转换为 MB
    return memSize / (1024.0 * 1024.0);
}

#pragma mark - private

/**
 * 获取系统内存压力值（0-1之间，越接近1表示内存压力越大）
 * @return 内存压力值
 */
- (double)p_getMemoryPressure 
{
    // 获取可用内存
    vm_statistics64_data_t vmStats;
    mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
    host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmStats, &count);
    
    // 计算内存压力
    double totalPages = vmStats.active_count + vmStats.inactive_count +
                        vmStats.wire_count + vmStats.free_count;
    double usedPages = vmStats.active_count + vmStats.wire_count;
    
    return usedPages / totalPages;
}

- (void)p_addMemoryUsageToHistory:(double)usage
{
    [self.lock lock];
    //记录最近100条，大概是 200s 的数据
    if (self.memoryUsageHistory.count > 100) {
        [self.memoryUsageHistory removeObjectAtIndex:0];
    }
    [self.memoryUsageHistory addObject:@(usage)];
    [self.lock unlock];
}

- (void)p_receiveMemoryWarning:(NSNotification *)noti
{
    double memoryUsage = [self currentMemoryUsage];
    double totalMemory = [self totalDeviceMemory];
    
    double percentage = (memoryUsage / totalMemory) * 100.0;
    NSLog(@"收到系统内存警告! 当前内存使用: %.2f MB (%.1f%%)", memoryUsage, percentage);
    
    NSArray *usageHistory;
    [self.lock lock];
    usageHistory = [self.memoryUsageHistory copy];
    [self.lock unlock];
    //生成报告
    [self p_generateMemoryWarningReport:memoryUsage
                             percentage:percentage
                                  level:ZYMemoryWarningLevelCritical
                           usageHistory:usageHistory];
}

/**
 * 处理内存警告
 * @param level 警告级别
 * @param memoryUsage 当前内存使用量（MB）
 * @param percentage 内存使用百分比
 */
- (void)p_handleMemoryWarning:(ZYMemoryWarningLevel)level
                  memoryUsage:(double)memoryUsage
                   percentage:(double)percentage
{
    [self.lock lock];
    
    CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
    
    // 如果是同一级别的警告、或者中等级的警告，至少间隔30秒才再次报告
    if (level == self.lastWarningLevel && currentTime - self.lastWarningTime <= 30) {
        [self.lock unlock];
        return;
    }
    self.lastWarningTime = currentTime;
    self.lastWarningLevel = level;
    
    switch (level) {
        case ZYMemoryWarningLevelMiddle:
        {
            NSLog(@"内存使用接近警告阈值: %.2f MB (%.1f%%)", memoryUsage, percentage);
            break;
        }
                
                
        case ZYMemoryWarningLevelHigh:
        {
            NSLog(@"内存使用超过警告阈值: %.2f MB (%.1f%%)", memoryUsage, percentage);
            // 生成内存警告报告
            [self p_generateMemoryWarningReport:memoryUsage
                                     percentage:percentage
                                          level:level
                                   usageHistory:[self.memoryUsageHistory copy]];
            break;
        }
                
        default:    break;
    }
    
    [self.lock unlock];
}

/**
 * 生成内存警告报告
 * @param memoryUsage 当前内存使用量（MB）
 * @param percentage 内存使用百分比
 * @param level 警告级别
 */
- (void)p_generateMemoryWarningReport:(double)memoryUsage
                           percentage:(double)percentage
                                level:(ZYMemoryWarningLevel)level
                         usageHistory:(NSArray *)usageHistory
{
    // 构建异常名称和原因
    NSString *name = @"Memory Warning";

    NSString *levelString = @"未知";
    switch (level) {
        case ZYMemoryWarningLevelMiddle:
            levelString = @"中度";
            break;
        case ZYMemoryWarningLevelHigh:
            levelString = @"高度";
            break;
        case ZYMemoryWarningLevelCritical:
            levelString = @"严重";
            name = @"System Memory Warning";
            break;
        default:
            break;
    }

    NSString *reason = [NSString stringWithFormat:@"内存使用量: %.2f MB (%.1f%%), 警告级别: %@",
                        memoryUsage, percentage, levelString];
    // 收集额外信息
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    userInfo[@"memoryUsage"] = @(memoryUsage);
    userInfo[@"memoryPercentage"] = @(percentage);
    userInfo[@"level"] = @(level);
    userInfo[@"levelString"] = levelString;
    userInfo[@"memoryHistory"] = [usageHistory copy];
    
    // 添加应用状态信息
    UIApplicationState appState = [UIApplication sharedApplication].applicationState;
    userInfo[@"applicationState"] = @(appState);
    
    // 添加设备信息
    NSProcessInfo *processInfo = [NSProcessInfo processInfo];
    userInfo[@"systemUptime"] = @(processInfo.systemUptime);
    userInfo[@"processorCount"] = @(processInfo.processorCount);
    userInfo[@"activeProcessorCount"] = @(processInfo.activeProcessorCount);
    userInfo[@"physicalMemory"] = @(processInfo.physicalMemory / (1024.0 * 1024.0)); // MB
    
    // 添加内存压力信息
    double memoryPressure = [self p_getMemoryPressure];
    userInfo[@"memoryPressure"] = @(memoryPressure);
    
    // 添加虚拟内存信息
    mach_task_basic_info_data_t taskInfo;
    mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
    kern_return_t kr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&taskInfo, &count);
    if (kr == KERN_SUCCESS) {
        userInfo[@"residentMemory"] = @(taskInfo.resident_size / (1024.0 * 1024.0)); // MB
        userInfo[@"virtualMemory"] = @(taskInfo.virtual_size / (1024.0 * 1024.0)); // MB
    }
    
    // 生成崩溃报告
    [[ZYCrashReportGenerator sharedInstance] generateReportWithType:ZYCrashTypeMemoryWarning
                                                               name:name
                                                             reason:reason
                                                           userInfo:userInfo];
    
}
@end
